home *** CD-ROM | disk | FTP | other *** search
- ## -*-Tcl-*- nowrap
- # ###################################################################
- # AlphaTcl - core Tcl engine
- #
- # FILE: "ISOTime.tcl"
- # created: 1999-08-17 13:46:06
- # last update: 2/7/2001 {9:27:38 PM}
- # Author: Frédéric Boulanger
- # E-mail: Frederic.Boulanger@supelec.fr
- # mail: Supélec - Service Informatique
- # Plateau de Moulon, 91192 Gif-sur-Yvette cedex, France
- # www: http://wwwsi.supelec.fr/fb/fb.html
- #
- # Description:
- # This extension adds new choices for the second parameter (format)
- # of the 'mtime' command. "mtime [now] iso" returns the current time
- # in ISO format, i.e. "1999-08-17T14:55:22Z" for August 17 1999 at
- # 2:55:22 pm.
- # To be a real ISO format, the final "Z" should be the local time
- # zone, but I don't know how to get it in Alpha, so I use "Z" which
- # means "UTC" or universal time.
- # Using "relaxed" instead of "iso" yields a more readable date with
- # a space in place of the 'T' and without the final 'Z'.
- #
- # The other choices are 'year', 'month', 'day', 'hour', 'minutes',
- # and 'seconds' to get the respective piece of time information.
- #
- # Note: This extension may yield incorrect results if you change the
- # time format in the 'Date and Time' control panel while Alpha is running.
- #
- # The effective format of the localized time representation is
- # determined by the ISOTime::parseLocalizedTime proc which is called
- # only once for the sake of efficiency.
- #
- # If this behaviour may cause problem and you don't use the ISOTime
- # procs too often, you may remove the check for ISOTime::regdate and
- # ISOTime::matchdate at the beginning of ISOTime::brokenDate so that
- # it rebuilds the regexps at each call.
- #
- # History
- #
- # modified by rev reason
- # ---------- --- --- -----------
- # 1999-08-17 FBO 1.0 original
- # 1999-08-18 FBO 1.1 added year, month ... keywords for direct access
- # 1999-08-26 FBO 1.2 made the date&time really ISO (YYYY-MM-DDTHH:MM:SSZ)
- # 1999-09-02 VMD 1.3 made work with Alphatk, and fixed some Tcl8 isms
- # 1999-11-04 FBO 1.4 added "relaxed" for a more readable ISO format
- # ###################################################################
- ##
- alpha::extension isoTime 1.4 {
- # Time-stamps are in ISO or a shorter, more readable format.
- newPref variable timeStampStyle short global "" "short iso relaxed"
- lunion varPrefs(International) timeStampStyle
- namespace eval ISOTime {}
- if {[info command ISOTime::__mtime] == ""} {
- rename mtime ISOTime::__mtime
- proc mtime {when {format "short"}} {
- switch -- $format {
- relaxed {ISOTime::ISODateAndTimeRelaxed $when}
- iso {ISOTime::ISODateAndTime $when}
- year -
- month -
- day -
- hour -
- minutes -
- seconds {
- ISOTime::brokenDate $when bdate
- return $bdate($format)
- }
- default {ISOTime::__mtime $when $format}
- }
- }
- }
- } maintainer {
- "Frédéric Boulanger" Frederic.Boulanger@supelec.fr <http://wwwsi.supelec.fr/fb/fb.html>
- } uninstall {this-file} help {
- This extension adds new choices for the second parameter
- (format) of the 'mtime' command. "mtime [now] iso" returns the
- current time in ISO format, i.e. "1999-08-17T14:55:22Z" for
- August 17 1999 at 2:55:22 pm.
-
- To be a real ISO format, the final "Z" should be the local time
- zone, but I don't know how to get it in Alpha, so I use "Z"
- which means "UTC" or universal time. Using "relaxed" instead
- of "iso" yields a more readable date with a space in place of
- the 'T' and without the final 'Z'.
-
- The other choices are 'year', 'month', 'day', 'hour',
- 'minutes', and 'seconds' to get the respective piece of time
- information.
-
- Note: This extension may yield incorrect results if you change
- the time format in the 'Date and Time' control panel while
- Alpha is running.
-
- The effective format of the localized time representation is
- determined by the ISOTime::parseLocalizedTime proc which is
- called only once for the sake of efficiency.
-
- If this behaviour may cause problem and you don't use the
- ISOTime procs too often, you may remove the check for
- ISOTime::regdate and ISOTime::matchdate at the beginning of
- ISOTime::brokenDate so that it rebuilds the regexps at each
- call.
- }
-
- # Determine the format of the localized time representation and build a
- # regular expression to extract each piece of information from this format.
- #
- # To get this information, I use the localized string representing
- # a known date: March 2 1904 at 5 am, 6 minutes and 7 seconds (5288767
- # MacOS ticks). In this string, I look for '2' which is the day of month,
- # for '3' which is the month, for '4' which is the year, for '5' which is
- # the minutes and for '7' which is the seconds.
- #
- # Once I got the indices of each piece of information in the string, I build
- # a list of 'XX YY info' items, where XX is the starting index, YY is the
- # ending index for the 'info' piece of information (day, month, year...).
- #
- # I sort this list so that I know in which order the time information is
- # given on the current localized version of MacOS.
- #
- # Then, I use this list to build a regular expression that matches the
- # localized representation of time, and a matching expression which will
- # set the items of the 'datevar' array to the corresponding time
- # information.
- #
- # March 2 1904 at 5 am, 6 minutes and 7 seconds is 5288767
- # April 3 1905 at 6 am, 7 minutes and 8 seconds is 39593228
- proc ISOTime::parseLocalizedTime {} {
- global ISOTime::regdate ISOTime::matchdate alpha::platform
-
- if {${alpha::platform} != "alpha"} {
- set known [ISOTime::__mtime -2043251572 short 1]
- } else {
- set known [ISOTime::__mtime 39593228]
- }
-
- regexp -indices {(.*[^0-9])*(0?3)[^0-9]*.*} $known z pr day
- regexp -indices {(.*[^0-9])*(0?4)[^0-9]*.*} $known z pr month
- # '20' is temporary fix for buggy dev version of Alpha
- regexp -indices {(.*[^0-9])*((19|20)?0?5)[^0-9]*.*} $known z pr year
- regexp -indices {(.*[^0-9])*(0?6)[^0-9]*.*} $known z pr hour
- regexp -indices {(.*[^0-9])*(0?7)[^0-9]*.*} $known z pr minutes
- regexp -indices {(.*[^0-9])*(0?8)[^0-9]*.*} $known z pr seconds
-
- set order ""
- lappend order "[format "%.2d" [lindex $day 0]] [format "%.2d" [lindex $day 1]] day"
- lappend order "[format "%.2d" [lindex $month 0]] [format "%.2d" [lindex $month 1]] month"
- lappend order "[format "%.2d" [lindex $year 0]] [format "%.2d" [lindex $year 1]] year"
- lappend order "[format "%.2d" [lindex $hour 0]] [format "%.2d" [lindex $hour 1]] hour"
- lappend order "[format "%.2d" [lindex $minutes 0]] [format "%.2d" [lindex $minutes 1]] minutes"
- lappend order "[format "%.2d" [lindex $seconds 0]] [format "%.2d" [lindex $seconds 1]] seconds"
- set order [lsort $order]
- set ISOTime::regdate ""
- set ISOTime::matchdate ""
- if {[lindex [lindex $order 0] 0] == 0} {
- append ISOTime::regdate {([0-9]*)}
- } else {
- append ISOTime::regdate [string range $known 0 0]
- }
- append ISOTime::matchdate "set date([lindex [lindex $order 0] 2]) \\1;"
- set tmp [ISOTime::int [lindex [lindex $order 0] 1] 1]
- append ISOTime::regdate "\\[string range $known $tmp $tmp]"
-
- append ISOTime::regdate {([0-9]*)}
- append ISOTime::matchdate "set date([lindex [lindex $order 1] 2]) \\2;"
- set tmp [ISOTime::int [lindex [lindex $order 1] 1] 1]
- append ISOTime::regdate "\\[string range $known $tmp $tmp]"
-
- append ISOTime::regdate {([0-9]*)}
- append ISOTime::matchdate "set date([lindex [lindex $order 2] 2]) \\3;"
- set tmp [ISOTime::int [lindex [lindex $order 2] 1] 1]
- append ISOTime::regdate "\\[string range $known $tmp $tmp]"
-
- append ISOTime::regdate {\{?([0-9]*)}
- append ISOTime::matchdate "set date([lindex [lindex $order 3] 2]) \\4;"
- set tmp [ISOTime::int [lindex [lindex $order 3] 1] 1]
- append ISOTime::regdate "\\[string range $known $tmp $tmp]"
-
- append ISOTime::regdate {([0-9]*)}
- append ISOTime::matchdate "set date([lindex [lindex $order 4] 2]) \\5;"
- set tmp [ISOTime::int [lindex [lindex $order 4] 1] 1]
- append ISOTime::regdate "\\[string range $known $tmp $tmp]"
-
- append ISOTime::regdate {([0-9]*)( [aApPmMUhr]+\})?}
- append ISOTime::matchdate "set date([lindex [lindex $order 5] 2]) \\6;"
- }
-
- # Extract time information from the MacOS ticks 'when', and put it
- # in the 'datevar' variable. This information is independent of the
- # time display format of your localized version of MacOS.
- #
- # Using 'regsub', I apply a regular expression to the localized
- # representation of 'when', and this builds the command that sets
- # the items of the 'datevar' array. I evaluate this command, and
- # 'datevar' now holds time information in a localization independent
- # form.
- # The regular expression and the transformation expression are built by the
- # ISOTime::parseLocalizedTime proc. To save time, this proc is called only if
- # the regular expressions are not defined. This assumes that you don't
- # change the date format while Alpha is running.
- #
- # The next step is to trim leading '0' so that the items of the array
- # are simple numbers.
- #
- # A final step adds 1900 or 2000 to the year if it is lower than 100.
- # I use the fact that the MacOS ticks 3029529600 represent
- # January 1st 2000 at 0 hour, 0 minutes and 0 seconds.
- #
- # brokenDate $when theDate sets 'theDate' so that:
- # theDate(year) contains the year of the 'when' MacOS ticks
- # theDate(month) contains the month of the 'when' MacOS ticks
- # theDate(day) contains the day of month of the 'when' MacOS ticks
- # theDate(hour) contains the hour of the 'when' MacOS ticks
- # theDate(minutes) contains the minutes of the 'when' MacOS ticks
- # theDate(seconds) contains the seconds of the 'when' MacOS ticks
- #
- # January 1st 2000 at 0:00:00 is 3029529600
-
- proc ISOTime::brokenDate {{when "now"} {datevar "theDate"}} {
- global ISOTime::regdate ISOTime::matchdate
- upvar $datevar date
-
- if {$when == "now"} {
- set theTicks [now]
- } else {
- set theTicks $when
- }
-
- if {(![info exists ISOTime::regdate]) || (![info exists ISOTime::matchdate])} {
- ISOTime::parseLocalizedTime
- }
-
- regsub [set ISOTime::regdate] [ISOTime::__mtime $theTicks] [set ISOTime::matchdate] dateCmd
- eval $dateCmd
-
- set date(year) [ISOTime::int $date(year)]
- set date(month) [ISOTime::int $date(month)]
- set date(day) [ISOTime::int $date(day)]
- set date(hour) [ISOTime::int $date(hour)]
- set date(minutes) [ISOTime::int $date(minutes)]
- set date(seconds) [ISOTime::int $date(seconds)]
-
- if {$date(year) < 100} {
- if {$theTicks < 3029529600} {
- set date(year) [expr $date(year) + 1900]
- } else {
- set date(year) [expr $date(year) + 2000]
- }
- }
- return $theTicks
- }
-
- # Work around peculiarity of Tcl that '09' is not an integer,
- # but a base 8 number, and that int(09) will give an error.
- proc ISOTime::int {what {plus 0}} {
- regsub {^0+([1-9])} $what \\1 what
- return [expr {int($what + $plus)}]
- }
-
- # Build an ISO representation of the date corresponding to the 'when' MacOS
- # ticks. Uses ISOTime::brokenDate to get a localization independent representation
- # of time. The ISO date is in the form 'YYYY-MM-DD'.
- proc ISOTime::ISODate {{when "now"}} {
- ISOTime::brokenDate $when curDate
- return "[format "%.4u" $curDate(year)]-[format "%.2u" $curDate(month)]-[format "%.2u" $curDate(day)]"
- }
-
- # Same with time added in the form 'THH:MM:SSZ'
- proc ISOTime::ISODateAndTime {{when "now"}} {
- ISOTime::brokenDate $when curDate
- return "[format "%.4u" $curDate(year)]-[format "%.2u" $curDate(month)]-[format "%.2u" $curDate(day)]T[format "%.2u" $curDate(hour)]:[format "%.2u" $curDate(minutes)]:[format "%.2u" $curDate(seconds)]Z"
- }
-
- # Same with time added in the form ' HH:MM:SS' (not strict ISO, but more readable
- proc ISOTime::ISODateAndTimeRelaxed {{when "now"}} {
- ISOTime::brokenDate $when curDate
- return "[format "%.4u" $curDate(year)]-[format "%.2u" $curDate(month)]-[format "%.2u" $curDate(day)] [format "%.2u" $curDate(hour)]:[format "%.2u" $curDate(minutes)]:[format "%.2u" $curDate(seconds)]"
- }